package api

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"

	"go-caipu/pkg/api/helper"
	"go-caipu/pkg/constant"
	"go-caipu/pkg/services/admin/config"
	storage "go-caipu/pkg/services/storage/models"
)

func (hs *HTTPServer) GetSysConfigPage(c *gin.Context) {
	cmd := config.GetSysConfigPageCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, count, err := hs.configService.GetSysConfigPage(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(c, helper.Page{CurrentPage: cmd.PageIndex, PageSize: cmd.PageSize, List: result, Total: count})
}

type appConfig struct {
	Label string `json:"label"`
	Value string `json:"value"`
}

// GetAppConfig 获取系统配置选项
func (hs *HTTPServer) GetAppConfig(c *gin.Context) {
	cmd := config.GetSysConfigPageCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, _, err := hs.configService.GetSysConfigPage(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	var arrResult []appConfig
	for _, item := range result {
		arrResult = append(arrResult, appConfig{Label: item.ConfigKey, Value: item.ConfigValue.(string)})
	}

	helper.SuccessWithData(c, result)
}

func (hs *HTTPServer) GetSysConfig(c *gin.Context) {
	cmd := config.GetSysConfigCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, err := hs.configService.Get(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(c, helper.Response{Code: constant.CodeSuccess, Data: result})
}
func (hs *HTTPServer) CreateSysConfig(c *gin.Context) {
	cmd := config.SysConfig{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	err := hs.configService.Insert(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

func (hs *HTTPServer) UpdateSysConfig(c *gin.Context) {
	cmd := config.SysConfig{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	err := hs.configService.Update(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}
func (hs *HTTPServer) SetSystemConfig(c *gin.Context) {
	var cmd []config.SysConfig
	if err := c.ShouldBindJSON(&cmd); err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	//批量更新:使用量不大，暂不考虑性能，后续优化
	for _, item := range cmd {
		set, err := hs.configService.Get(c.Request.Context(), config.GetSysConfigCommand{Id: item.ConfigId})
		if err != nil {
			continue
		}
		if strings.Contains(item.ConfigKey, "SITE_FAVICON") || strings.Contains(item.ConfigKey, "SITE_LOGO") {
			base64Data := item.ConfigValue.(string)
			if isSafeImage(base64Data) {
				path, err := saveSafeImage(hs, base64Data, strings.ToLower(strings.TrimPrefix(item.ConfigKey, "SITE_")))
				if err != nil {
					continue
				}
				set.ConfigValue = path
			}
		} else {
			set.ConfigValue = item.ConfigValue
		}

		err = hs.configService.Update(c.Request.Context(), set)
		if err != nil {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
			return
		}
	}
	helper.SuccessWithOutData(c)
}
func isSafeImage(contentType string) bool {
	allowedTypes := []string{
		"image/png",
		"image/jpeg",
		"image/gif",
		"image/svg+xml", // 需要额外处理 SVG
	}
	for _, t := range allowedTypes {
		if strings.Contains(contentType, t) {
			return true
		}
	}
	return false
}
func getExtensionFromContentType(contentType string) (string, error) {
	switch {
	case strings.Contains(contentType, "png"):
		return ".png", nil
	case strings.Contains(contentType, "jpeg"), strings.Contains(contentType, "jpg"):
		return ".jpg", nil
	case strings.Contains(contentType, "gif"):
		return ".gif", nil
	case strings.Contains(contentType, "svg+xml"):
		return ".svg", nil
	default:
		return "", fmt.Errorf("unsupported content type: %s", contentType)
	}
}

// 安全保存图片
func saveSafeImage(hs *HTTPServer, base64Data string, fileName string) (string, error) {
	parts := strings.SplitN(base64Data, ",", 2)
	if len(parts) != 2 {
		return "", fmt.Errorf("invalid base64 format")
	}
	contentType := parts[0] // "data:image/png;base64"
	base64Content := parts[1]

	// 获取正确的扩展名
	ext, err := getExtensionFromContentType(contentType)
	if err != nil {
		return "", err
	}

	// 生成文件名
	fileName = fmt.Sprintf("%s%s", fileName, ext)
	// 解码并保存文件
	decoded, err := base64.StdEncoding.DecodeString(base64Content)
	if err != nil {
		return "", fmt.Errorf("failed to decode base64: %v", err)
	}
	params := storage.FileStorage{FileName: fileName, FileSize: int64(len(decoded))}
	err = hs.storageService.Upload(context.Background(), &params, bytes.NewReader(decoded))

	//创建输出文件
	return fmt.Sprintf("/api/file/%s", params.FileKey), nil
}
func (hs *HTTPServer) RemoveSysConfig(c *gin.Context) {
	cmd := config.RemoveSysConfigCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	err := hs.configService.Remove(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

type Option struct {
	Code  string `json:"code"`
	Value string `json:"value"`
}

// swagger:route GET /system/option  GetConfigMap
//
// 系统设置.
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (hs *HTTPServer) GetConfigMap(c *gin.Context) {
	codes := c.QueryArray("code")
	cmd := config.GetConfigsByKeyCommand{Code: codes, Category: c.Query("category")}

	if len(codes) == 0 && cmd.Category == "" {
		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, errors.New("param:(code Or Category) is nil"))
		return
	}
	items, _ := hs.configService.GetConfigsByKey(c, cmd)
	//for _, item := range items {
	//	result = append(result, Option{Code: item.ConfigKey, Value: item.ConfigValue})
	//}
	helper.SuccessWithData(c, items)
}

type ConfigValue struct {
	Label string `json:"label"`
	Value string `json:"value"`
}

// swagger:route GET /common/option  GetConfigsByKey
//
// 查询配置代码信息.
//
// 注意：此接口只返回配置代码信息，后端敏感信息不通过此接口返回.
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (hs *HTTPServer) GetConfigsByKey(c *gin.Context) {
	cmd := config.GetConfigsByKeyCommand{Category: c.Param("code")}
	if cmd.Category == "" {
		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, errors.New("param:(code Or Category) is nil"))
		return
	}

	var result []ConfigValue
	items, _ := hs.configService.GetConfigsByKey(c, cmd)

	for _, item := range items {
		result = append(result, ConfigValue{Label: strings.ToUpper(item.ConfigKey), Value: item.ConfigValue.(string)})
	}

	helper.SuccessWithData(c, result)
}
